import gradio as gr
from user_functions import *
import time

# 初始化状态变量，存储全局数据
app_state = {"db": None, "tables": []}

# 直接从数据库获取表格列表
def get_tables_direct(db_name):
    from user_utils import Tools
    t = Tools()
    tables = t.show_tables(db_name)
    print(f"直接从数据库获取到表: {tables}")
    return tables or []

with gr.Blocks(theme='soft', title='NLP to SQL') as demo:
    with gr.Row():
        gr.HTML("<h2>🔎 NLP to SQL 查询工具</h2>")
    
    # 查询所有的数据库
    with gr.Row():
        # 获取数据库列表
        db_list = show_databases()
        print(f"数据库列表: {db_list}")
        
        databases_dp = gr.Dropdown(
            choices=["" ] + db_list,  # 添加空选项
            label='选择数据库', 
            value="",  # 默认为空
            interactive=True
        )
    
    # 显示数据库下的数据表
    with gr.Row():
        query_tables = gr.CheckboxGroup(
            choices=['请先选择数据库'], 
            label='选择查询表', 
            visible=True
        )

    # 显示查询结果
    with gr.Row():
        query_result = gr.Dataframe(label='Query Result', visible=False)

    # 图表展示
    with gr.Row():
        vis_result = gr.Gallery(label='Visualization', visible=False)

    # 功能区按钮
    with gr.Row():
        with gr.Column(scale=1):
            # SQL or Code
            generate_model = gr.Radio(label='Generate Mode', choices=[
                                      'SQL', 'Code'], value='SQL')

        with gr.Column(scale=3):
            # user prompt
            user_input_text = gr.Text(label='Input Your Question')

        with gr.Column(scale=1):
            generate_sql_bt = gr.Button(
                value='Generate SQL', visible=True, size='lg', scale=1, variant='primary',)
            generate_code_bt = gr.Button(
                value='Generate Code', visible=False, scale=1)

    with gr.Row():
        # sql
        generate_text = gr.Code(
            label='Query SQL', interactive=False, visible=False, scale=1, language='sql-mySQL')

    with gr.Row():
        execute_code_bt = gr.Button(value='Execute Python Code', visible=False)

    # 定义数据库选择回调函数 - 兼容版本
    def on_database_change(db_name):
        print(f"\n=== 数据库选择事件: '{db_name}' ===\n")
        
        # 检查数据库名称是否有效
        if not db_name or db_name == "":
            print("  没有选择数据库")
            app_state["db"] = None  # 清除数据库选择
            app_state["tables"] = []  # 清除表格选择
            print("  状态已重置")
            # 返回新的组件实例而不是使用update方法
            return gr.CheckboxGroup(
                choices=['请先选择数据库'],
                label='选择查询表',
                visible=True
            )
        
        # 重要: 首先保存选择的数据库
        app_state["db"] = db_name
        
        # 同步全局state的状态
        from user_functions import state as user_state
        user_state.value['db'] = db_name
        
        print(f"  已保存数据库选择: {db_name}")
        print(f"  已同步到user_functions模块: {user_state.value['db']}")
        
        # 直接从数据库获取表格
        try:
            tables = get_tables_direct(db_name)
            app_state["tables"] = tables
            
            if not tables or len(tables) == 0:
                print(f"  警告: 数据库 '{db_name}' 没有表")
                user_state.value['tables'] = []
                return gr.CheckboxGroup(
                    choices=["此数据库没有表"],
                    label=f'选择查询表 (数据库 {db_name} 空)',
                    visible=True
                )
            
            print(f"  成功: 找到 {len(tables)} 个表: {tables}")
            # 返回新的组件实例
            return gr.CheckboxGroup(
                choices=tables,
                label=f'选择查询表 (共{len(tables)}个表)',
                visible=True,
                interactive=True
            )
            
        except Exception as e:
            print(f"  错误: 获取表格失败: {e}")
            user_state.value['tables'] = []
            return gr.CheckboxGroup(
                choices=[f"错误: {str(e)}"],
                label='选择查询表 (出错)',
                visible=True
            )
    
    # 绑定数据库选择事件 - 使用队列确保顺序执行
    databases_dp.change(
        fn=on_database_change,
        inputs=databases_dp,
        outputs=query_tables,
        show_progress=True,
        queue=True  # 使用队列确保完整处理
    )

    # 选中数据表后触发的操作
    query_tables.change(fn=query_tables_change, inputs=query_tables)

    # 生成模式改变后触达的操作
    generate_model.change(fn=generate_model_change, inputs=generate_model, outputs=[
                          generate_sql_bt, generate_code_bt])

    # 点击生成sql按钮触发的操作
    generate_sql_bt.click(fn=generate_sql_bt_click, inputs=user_input_text, outputs=[
                          generate_text, query_result])

    # 点击生成code按钮触发的操作
    generate_code_bt.click(fn=generate_code_bt_click, inputs=[
                           user_input_text, query_result], outputs=[generate_text, execute_code_bt])

    # 点击执行code按钮触发的操作
    execute_code_bt.click(fn=execute_code_bt_click,
                          inputs=generate_text, outputs=vis_result)

if __name__ == '__main__':
    # 打印当前的数据库配置信息
    print("=== 应用程序启动 ===")
    print("1. 尝试连接数据库...")
    from user_utils import Tools, DB_CONFIG
    test_tools = Tools()
    
    # 测试数据库连接
    try:
        databases = test_tools.show_databases()
        print(f"2. 数据库连接成功, 可用数据库: {databases}")
    except Exception as e:
        print(f"2. 数据库连接失败: {e}")
        print(f"   数据库配置: {DB_CONFIG}")
    
    print("3. 准备可视化目录...")
    # 准备可视化目录 - 使用相对路径
    import os
    current_dir = os.path.dirname(os.path.abspath(__file__))
    vis_dir = os.path.join(current_dir, 'visualization')
    
    if not os.path.exists(vis_dir):
        os.makedirs(vis_dir)
        print(f"   创建可视化目录: {vis_dir}")
    else:
        print(f"   可视化目录已存在: {vis_dir}")
        
    # 在可视化目录中创建测试文件以确认权限
    try:
        test_file = os.path.join(vis_dir, 'test_file.txt')
        with open(test_file, 'w') as f:
            f.write('Test file to verify write permissions')
        print(f"   测试文件写入成功: {test_file}")
        os.remove(test_file)  # 测试后删除
    except Exception as e:
        print(f"   警告: 无法写入测试文件: {e}")
    
    print("4. 启动Gradio界面...")
    # 启动应用，并配置指定的可视化目录
    demo.launch(
        debug=True, 
        allowed_paths=[vis_dir],
        show_error=True
    )
    
    '''
    统计订单数量排名前10的商品，返回商品名称和订单数量
    将以上统计出的数据绘制为饼状图，并按照要求进行保存
    '''